vue3新语法

vue3特点

https://www.bilibili.com/video/BV1VK4y1o7GS?from=search&seid=9785264573525132044

Vue2与Vue3 最大的区别 — Vue2使用选项类型API(Options API)对比Vue3合成型API(Composition API)
作用: 聚合代码 & 逻辑重用

一、知识点

  1. 使用defineComponent 构建应用及绑定事件
  2. 使用setup(props,content)父子通信
  3. 使用 reactive 绑定数据
  4. 使用 ref ( torefs ) 绑定数据
  5. 使用 getCurrentInstance 获取当前实例化对象上下文信息
  6. watch、watchEffect 数据监听
  7. 生命周期+axios数据请求
  8. 简单的 TodoList 点餐功能

1.使用 reactive 绑定数据

<template>
  <div>
    <h1>使用 reactive 绑定数据</h1>
    <p>{{state.msg}}</p>
    <p>{{info}}</p>
    <p>
      <button @click="changeMsg">changeMsg</button>
    </p>
  </div>
</template>
<script>

// Hooks 编程,在 vue 中导入对应的函数方法,面向函数式进行编程
// Vue-composition-API 这里就是Vue2与Vue3 最大的区别 — Vue2使用选项类型API(Options API)对比Vue3合成型API(Composition API)

import { defineComponent, reactive } from "vue";
export default defineComponent({
  name: 'test1',
  setup() {  // setup钩子函数
    // 使用响应式函数reactive构建proxy响应式对象state
    const state = reactive({
      msg: '时光'
    })
    console.log(state); // state对象是一个proxy拦截对象
    let info = 'hello'; // info是一个普通对象,修改后不会被proxy拦截,进而页面也不会动态更新
    const changeMsg = () => { // 在外边定义methods
      state.msg = '时光,你好'
      info = 'hello,你好'
    }
    return {  // 使用时,要把对象return出去,才能在template中使用
      state,
      info,
      changeMsg
    }
  }
})
</script>

2. setup()函数 完成父子通信

1. setup(props)第一个参数props

setup函数接收props作为其第一个参数,props对象是响应式的(单向的父—>子),watchEffect或watch会观察和响应props的更新。不要对props对象进行解构,那样会失去响应性。在开发过程中,props对象对用户空间代码时不可变的,用户尝试修改props时会触发警告。

案例1:props作为setup的第一个参数

// 父组件 Home.vue
<template>
  <div class="home">
    <About :name="sendData"/>
  </div>
</template>
<script>
  import {ref} from 'vue'; 
  import About from './About'
  export default{
    components:{
      About,
    },
    setup(){
      const sendData = ref('这世界很酷');
      return {
        sendData
      }
    }
  }
</script>

// 子组件About.vue
<template>
  <div class="about">
  {{propContent}}
  </div>
</template>
<script>
  import {watchEffect} from 'vue';
  export default{
    props:{
      name:String
    },
    setup(props){
      let propContent= props.name;
     // watchEffect(()=>{
     //   propContent = props.name
     //})
      return {
        propContent
      }
    }
  }
</script>

2. setup(props,context)第二个参数Context上下文对象

// 父组件 Home.vue
<template>
  <div class="home">
    <About :name="sendData.val" @name-changed=changeName>
      世界变化不停,人潮川流不息
    </About>
  </div>
</template>
<script>
  import {reactive} from 'vue';
  import About from './About';
  export default{
    components:{
      About,
    },
    setup(){
      const sendData = reactive({
        val:'sendData'
      })

      setTimeout(()=>{
        sendData.val+=1;
      },1000)

      function changeName(msg){
        console.log(`子组件传递了${msg}过来`)
      }
      return {
        sendData,
        changeName,
      }
    }
  }
</script>

//子组件 About.vue
<template>
  <div class="about">
    <button @click="fn">子改父</button>
  </div>
</template>
<script>
  import {watch} from 'vue';
  export default {
    props:{
      name:String
    },
    setup(props, context) {
      console.log(context,"上下文");
      let num=100;
      let fn=()=>{
        content.emit('name-changed',num)//相当于this.$emit()
       }
      return {
          fn
        }
    );
    },
  }
</script>

3.使用 ref、toRefs 绑定数据

<template>
  <div>
    <p>使用v-model双向数据绑定的数据内容是:{{ msg }}</p>
    <p>
      <!-- 自己实现双向数据绑定,监听input事件,动态修改nmsg的值 -->
      <input type="text" ref="myInput" @input="input" :value="nmsg" />
    </p>
    <p>使用@input事件动态实现双向数据绑定的数据内容是:{{ nmsg }}</p>
    <p>
      <!-- 使用ref方法动态定义并双向绑定hmsg -->
      <input type="text" v-model="hmsg" @input="hmagInpu" />
    </p>
    <p>使用ref方法动态定义并双向数据绑定的数据hmsg是:{{ hmsg }}</p>
    <p>toRefs 来实现在模板中不需要追加 state 调用数据:{{ msg }}</p>
  </div>
</template>
<script>
import {
  defineComponent,
  reactive,
  getCurrentInstance,
  toRefs,
  ref,
  computed,
} from "vue";

export default defineComponent({
  setup() {
    const state = reactive({
      msg: "",
      nmsg: "",
      cmsg: computed(() => {
        // 1.计算属性
        return state.msg.length;
      }),
    });

    // 2.可以使用getCurrentInstance hook 来拿到当前实例化对象上下文信息,但是除非极其特殊的情况,否则不建议这样使用
    const { ctx } = getCurrentInstance();
    const input = () => {
      // 在vue3中,因为是面向hooks函数编程,所以,无法通过this拿到当前vue实例化对象
      console.log(ctx.$refs.myInput.value); // 像使用vue2中的this一样,使用ctx(上下文内容信息)
      state.nmsg = ctx.$refs.myInput.value;
    };

    // 3.使用ref方法来定义一个响应式监听的对象,在实际开发中我们都是用这种方法来构建响应式对象
    const hmsg = ref("abc");
    const hmagInpu = () => {
      // 在内部使用hmsg的值,需要使用value来获取对应的值
      console.log("获取到的hmsg值是:" + hmsg.value);
    };

    return {
      // 4.使用toRefs hook方法方便,访问msg不需要使用state.msg,直接msg就可以获取到
      ...toRefs(state),
      hmsg,
      input,
      hmagInpu,
    };
  },
});
</script>


小结:两种构建响应式对象的方法
1.reactive

1.reactive方法,直接传入一个对象 state ,这个对象就是 proxy 拦截的对象
2.然后再把这个 state 对象直接 return 出去就能被调用
3.在 temolate 中使用 state.msg 来访问
4.在 js 中也使用 state.msg 来访问

2.ref

1.使用 ref 直接声明一个 proxy 响应式对象 msg
2.然后把这个 msg 对象直接 return 出去
3.在 template 中直接使用 {{msg}}
4.注意:在 js 中需要使用 msg.value

4.watch、watchEffect 数据监听

<template>
  <div>
    <h1>watch、watchEffect 数据监听</h1>
    <p>{{ msg }}</p>
    <p>{{ msg2 }}</p>
    <p>{{ info }}</p>
    <p>
      <button @click="changeMsg">changeMsg</button>
    </p>
    <p>
      <button @click="changeMsg2">changeMsg2</button>
    </p>
  </div>
</template>
<script>
import { defineComponent, reactive, watchEffect, watch, toRefs } from "vue";

export default defineComponent({
  name: "watch",
  // setup钩子函数
  setup() {
    // 使用响应式函数reactive构建proxy响应式对象state
    const state = reactive({
      msg: "时光",
      msg2: "kity",
      changeMsg2: () => {
        state.msg2 = "kity,你好";
      },
    });
    const changeMsg = () => {
      // 在外边定义methods
      state.msg = "时光,改变";
      info = "hello,改变";
    };
    let info = "hello";
    // watch监听只能是 getter/effect 函数、ref、reactive对象或数组
    // 简单监听
    watch(state, () => {
      console.log("观察整个state中属性变化", state.msg); // 只要state中的值有变化,就会打印
    });
    // 监听指定的信息
    watch(
      () => state.msg,
      (newVal, oldVal) => {
        console.log("01-msg的新值是:" + newVal + "-------旧值是:" + oldVal);
      }
    );
    // 监听多个属性(数组形式)
    watch([() => state.msg, () => state.msg2], (newVal, oldVal) => {
      console.log("02-msg的新值是:" + newVal + "-------旧值是:" + oldVal); // 02-msg的新值是:时光,你好,俞亮-------旧值是:时光,俞亮
    });
    // 不需要指定监听的属性
    watchEffect(() => {
      // 程序运行时,初始化就会执行一次,完成监听准备工作
      console.log("03-watchEffect监听 state 中数据变化:", state.msg); // 有点像computed计算属性,用到的数据发生改变才会执行
    });

    // 使用时,要把对象return出去,才能在template中使用
    return {
      ...toRefs(state),
      info,
      changeMsg,
    };
  },
});
</script>






5.生命周期

  1. setup() :开始创建组件之前,在beforeCreate和created之前执行。创建的是data和method
  2. onBeforeMount() : 组件挂载到节点上之前执行的函数。
  3. onMounted() : 组件挂载完成后执行的函数。
  4. onBeforeUpdate(): 组件更新之前执行的函数。
  5. onUpdated(): 组件更新完成之后执行的函数。
  6. onBeforeUnmount(): 组件卸载之前执行的函数。
  7. onUnmounted(): 组件卸载完成后执行的函数
  • 若组件被<keep-alive>包含,则多出下面两个钩子函数。
  1. onActivated(): 被包含在中的组件,会多出两个生命周期钩子函数。被激活时执行 。
  2. onDeactivated(): 比如从 A组件,切换到 B 组件,A 组件消失时执行。
Vue2--------------vue3
beforeCreate  -> setup()
created       -> setup()
beforeMount   -> onBeforeMount
mounted       -> onMounted
beforeUpdate  -> onBeforeUpdate
updated       -> onUpdated
beforeDestroy -> onBeforeUnmount
destroyed     -> onUnmounted
activated     -> onActivated
deactivated   -> onDeactivated

使用写法

    let {ref, onBeforeMount, onMounted, onBeforeUpdate, onUpdated, onBeforeUnmount, onUnmounted, onErrorCaptured, onRenderTracked, onRenderTriggered} = Vue;

export default {

 // setup相当于vue2中的beforeCreate和created,并且在两者之前执行
      setup(){
        let test = ref('测试')

        // 挂载开始之前被调用
        onBeforeMount(()=>{
          console.log('onBeforeMount',test)
        })

        // 实例被挂载后调用,不会保证所有的子组件也被挂载完
        onMounted(()=>{
          console.log('onMounted',test)
        })

        // DOM更新前
        onBeforeUpdate(()=>{
          console.log('onBeforeUpdate',test)
        })

        // DOM更新后,不会保证所有的子组件也都一起被重绘
        onUpdated(()=>{
          console.log('onUpdated', test)
        })

        // 卸载组件实例之前,此时实例仍然是完全正常的
        onBeforeUnmount(()=>{
          console.log('onBeforeUnmount', test)
        })

        // 卸载组件实例后调用。调用此钩子时,组件实例的所有指令都被解除绑定,所有事件侦听器都被移除,所有子组件实例被卸载。
        onUnmounted(()=>{
          console.log('onUnmounted', test)
        })

        // 当捕获一个来自子孙组件的错误时被调用
        onErrorCaptured(()=>{
          console.log('onErrorCaptured',test)
        })

        // 跟踪虚拟 DOM 重新渲染时调用
        onRenderTracked(()=>{
          console.log('onRenderTracked',test)
        })

        // 当虚拟 DOM 重新渲染为 triggered.Similarly 为renderTracked,接收 debugger event 作为参数。此事件告诉你是什么操作触发了重新渲染,以及该操作的目标对象和键。
        onRenderTriggered(()=>{
          console.log('onRenderTriggered',test)
        })

        return {test};
      }
}

vue3如何使用axios

  1. 安装vue add axios
  2. 删除main.js
    import './plugins/axios
  3. 使用
import axios from "axios";
onMounted(() => {
      fetch();
    });
    function fetch() {
      axios.get("http://jsonplaceholder.typicode.com/users").then((res) => {
        console.log(res);
      });
    }

6.TodoList

<template>
  <div>
    <h1>TodoList 点餐</h1>
    <h2>菜单列表</h2>
    <ul>
      <li v-for="(item, index) in list" :key="index">
        {{item.name}} 价格 {{item.price}}
        <button @click="add(index)">点餐</button>
      </li>
    </ul>
    <h2>已点菜单</h2>
    <ul>
      <li v-for="(item, index) in aList" :key="index">
        {{item.name}} 价格 {{item.price}}
        <button @click="remove(index)">取消</button>
      </li>
    </ul>
    <h3>一共点了 {{count}} 道菜,消费 {{allPrice}}</h3>
  </div>
</template>

<script>
import { defineComponent, reactive, computed, toRefs } from "vue";

export default defineComponent({
  setup() {
  
    // 浮点数相加处理
    const add = (num1, num2) => {
      // 将第一个数转成字符串,取小数点后的部分,记录小数点后的位数
      const a1 = ('' + num1).split('.')[1] ? ('' + num1).split('.')[1].length : 0;
      const a2 = ('' + num2).split('.')[1] ? ('' + num2).split('.')[1].length : 0;
      // 取较大的位数,获得10的指数幂
      const m = Math.pow(10, Math.max(a1, a2));
      // 处理成整数相加,再除以指数
      return (num1 * m + num2 * m) / m;
    }
    
    const state = reactive({
      list: [
        {
          name: '四喜丸子',
          price: 20.88
        },
        {
          name: '狮子头',
          price: 30.88
        },
        {
          name: '辣子鸡',
          price: 40.88
        },
        {
          name: '糖醋鲤鱼',
          price: 50.88
        },
      ],
      aList: [],
      count: computed(() => {
        return state.aList.length;
      }),
      allPrice: computed(() => {
        let allPrice = 0;
        state.aList.map(item => {
          // allPrice += item.price // js 中,浮点数相加会与实际结果有差异,因为在 js 编译的过程中,浮点数保存并不是精确的
          allPrice = add(allPrice, item.price);
        })
        return allPrice
      }),
      add: (index) => {
        console.log('你点的是:', state.list[index]);
        state.aList.push(state.list[index]);
      },
      remove: (index) => {
        console.log('你取消了:', state.aList[index]);
        state.aList.splice(index, 1)
      }
    })
    return {
      ...toRefs(state)
    }
  }
})
</script>

<style lang="scss" scoped>
  li{
    margin:20px;
  }
</style>


  • 32
    点赞
  • 132
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 8
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 8
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

star@星空

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值